package data

import (
	"os"
	"strings"
)

type Config struct {
	FilePath    string
	KeyValueMap map[string]string // k => v  保存所有k v数据对
	IndexKeyMap map[int]string    // i => k 保存所有 有key的行对应的i
	allLines    []string          //保存文件中所有行 注意，不应该由外部使用····················
}

func GenerateConfig(fileName string) (Config, error) {
	conf := Config{fileName, map[string]string{}, map[int]string{}, []string{}}
	if !FileExist(fileName) {
		return conf, filePutContents(fileName, "")
	} else {
		conf.Parse()
		return conf, nil
	}
}

func (conf *Config) AddLine(line string) *Config {
	conf.allLines = append(conf.allLines, line)
	return conf
}

func (conf *Config) AddKVLine(k, v string) *Config {
	conf.KeyValueMap[k] = v
	conf.IndexKeyMap[len(conf.allLines)] = k
	conf.allLines = append(conf.allLines, k+":"+v)
	return conf
}

func (conf *Config) RemoveLine(lineIndex int) {
	if key, ok := conf.IndexKeyMap[lineIndex]; ok {
		delete(conf.KeyValueMap, key)
		delete(conf.IndexKeyMap, lineIndex)
	}
	//以下代码删除allLines中序号为lineIndex的元素
	j := 0
	for i, v := range conf.allLines {
		if i != lineIndex {
			conf.allLines[j] = v
			j++
		}
	}
	conf.allLines = conf.allLines[:j]
}

func (conf *Config) RemoveKVLine(k string) {
	for i, _k := range conf.IndexKeyMap {
		if k == _k {
			conf.RemoveLine(i)
		}
	}
}

func (conf *Config) parseFromString(str string) {
	str = strings.TrimSpace(str)
	arr := strings.Split(str, "\n")
	for i, v := range arr {
		v = strings.TrimSpace(v)
		splitIndex := strings.IndexByte(v, ':')
		if splitIndex >= 0 {
			cuts := [2]string{v[:splitIndex], v[splitIndex+1:]}
			conf.KeyValueMap[cuts[0]] = cuts[1]
			conf.IndexKeyMap[i] = cuts[0]
		}
		conf.allLines = append(conf.allLines, v)
	}
}

func (conf *Config) Parse() error {
	str, err := fileGetContents(conf.FilePath)
	if err != nil {
		if os.IsExist(err) {
			return err
		} else {
			return nil
		}
	}
	conf.parseFromString(str)
	return nil
}

func (conf *Config) SerializeToString() string {
	var strBuilder strings.Builder
	for i, v := range conf.allLines {
		if key, ok := conf.IndexKeyMap[i]; ok {
			strBuilder.WriteString(key + ":" + conf.KeyValueMap[key] + "\n")
		} else {
			strBuilder.WriteString(v + "\n")
		}
	}
	return strBuilder.String()
}

func (conf *Config) SerializeToFile() error {
	str := conf.SerializeToString()
	return filePutContents(conf.FilePath, str)
}

func FileExist(path string) bool {
	_, err := os.Lstat(path)
	return !os.IsNotExist(err)
}

func filePutContents(filepath, contents string) error {
	f, err := os.Create(filepath)
	defer f.Close()
	if err != nil {
		return err
	}
	f.WriteString(contents)
	return nil
}

func fileGetContents(filepath string) (string, error) {
	b, err := os.ReadFile(filepath)
	if err != nil {
		return "", err
	}
	return string(b), nil
}
